/*
 * This project is for 4G backup l2tp 
 *
*/


#include "l2tp.h"
#include "list.h"
#include "header.h"

struct kool_list
{
    int to;
    struct list_head list;
    int from;
};

struct l2tp_info
{
	char l2tp_inface_name[SIZE_64] ;	//l2tp's interface name
	char tunnel_id[SIZE_32] ; 		//local tunnel id ;
	char peer_tunnel_id[SIZE_32] ; 		//peer tunnel id 	
	char session_id[SIZE_32] ;		//local session id 
	char peer_session_id[SIZE_32] ;		//remote session id
	char local_ip[SIZE_64] ;		//local ip address
	char remote_ip[SIZE_64] ;		//remote ip address
	char source_port[SIZE_32] ;		//source port
	char dest_port[SIZE_32] ;			//destination port
	char mac_addr[SIZE_64] ;		//peer MAC address
	char inface_name[SIZE_64] ;			//this side's vlan id .link with the l2tp interface
	char vlan_id[SIZE_128] ;
//	struct l2tp_info *next ;
	struct list_head list ;
};

/*	Define thie global local Ip	
*	And they init in the main function
*/
char localIp[SIZE_32] ; 

int tunnel_id_flag ;
int session_id_flag ;
int source_port_flag ;
int name_flag ;

struct l2tp_info head ;
struct l2tp_info *tmp ;
struct list_head *pos;

int vlan_num  ;
//struct l2tp_info *head ;

void create_sokect(int sockfd, int port)
{
	struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(port); //PEER_LISTEN_PORT
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	int on = 1;
	setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
	
    if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
    {
        perror("bind");
        exit(1);
    }

    if(listen(sockfd, 10) == -1)
    {
        perror("listen");
        exit(1);
    }
}

int change_public_ip(char ipaddr[])
{
	struct list_head *pos;
	
	list_for_each(pos, &head.list)
    {
        tmp= list_entry(pos, struct l2tp_info, list);
		
		memset(tmp->local_ip, 0, sizeof(tmp->local_ip));
		sprintf(tmp->local_ip, "%s", ipaddr);
        //printf("read from file ,inface_name= %s vlan_id= %s\n", tmp->inface_name, tmp->vlan_id);
    }
    printf("\n");
	
	return 1 ;
} 

int snmp_handle_vlan(char *parse[])
{
	struct l2tp_info *vlan  ;
	struct l2tp_info *del = NULL;
	struct list_head *pos, *q;
	
	char *action = trim(parse[1]) ;
	char *inface_name = trim(parse[2]) ;
	char *vlan_id = trim(parse[3]) ;
	char *mac_addr = trim(parse[4]) ;
	char cmd[SIZE_128] ;
	char inface_vlan_id[SIZE_64];
	char *tok_vid ;
	char popen_result[SIZE_512]; 
	int status = 0 ;
	
	FILE *fp ;
	
	//sprintf(vlan->inface_name, "%s", trim(parse[2]));
	if ((inface_name == NULL) || (vlan_id == NULL) || (mac_addr == NULL))
	{
		printf("name ,mac addr or id is null ,return 0\n");
		return 0 ;
	}

	// add mac verify here ;
	
	/* Give a judge for the interface name and vlan id 
	*	limit it into SIZE_128. It can also be expanded by hand.
	*/
	
	if(strlen(inface_name) + strlen(vlan_id) > SIZE_128)
	{
		printf("Too large size interface name and vlan id \n");
		return 0 ;
	}
	
	/*
	*	parse[1] contain the action ,add/rem ;
	*	parse[2] is interface name ; parse[3] is vlan id ;
	*	if action is ADD, we put it %s %s ;
	*	else action is DEL, we put is %s.%s ;
	*/
	
	tok_vid = strtok(vlan_id, ",");
	
	while(tok_vid != NULL )
	{	
		// Initilaze link_list head ;
		/*	It must malloc a space for this struct ;	*/
		vlan = (struct l2tp_info *)malloc (sizeof(struct l2tp_info)) ;
		memset(vlan, 0, sizeof(struct l2tp_info));
		if(vlan == NULL){
			perror("malloc error");
			exit(1) ;
		}

		memset(vlan->mac_addr, 0, sizeof(vlan->mac_addr));
		
		sprintf(vlan->inface_name, "%s", inface_name);
		sprintf(vlan->vlan_id, "%s", tok_vid);
		sprintf(vlan->mac_addr, "%s", mac_addr);
		sprintf(vlan->local_ip, "%s", localIp) ;
		
		if(!strcmp(trim(action), SNMP_ADD)) 
		{
			sprintf(inface_vlan_id, "%s %s", vlan->inface_name, tok_vid) ;
		} 
		else if ( !strcmp(trim(action), SNMP_DEL))
		{
			sprintf(inface_vlan_id, "%s.%s", vlan->inface_name, tok_vid) ;
		}
		else	
		{
			printf("None action \n");
			return 0 ;
		}

		memset(cmd ,0 ,sizeof(cmd)) ;
		sprintf(cmd ,"vconfig %s %s", action, inface_vlan_id);
		printf("cmd: %s\n", cmd);
		
		fp = mypopen(cmd , 'r');
		memset(popen_result, 0 , sizeof(popen_result)) ;
		fgets(popen_result, sizeof(popen_result), fp);
		
		printf("popen_result:-%s-\n", popen_result);
		
		/*This place , judge the commond run success or not ;
		* if the result buffer is null , run error ; */	
		if (!strcmp(popen_result, "")){
			printf("vconfig %s success \n", trim(action));
			if(!strcmp(trim(action), SNMP_ADD)) 
			{
				vlan_num ++ ;
				list_add_tail(&(vlan->list), &(head.list));
	
			//	printf("inser ...inface name:%s, vid: %s\n", head.inface_name, head.vlan_id);
				status = 1 ;
			}
			else if (!strcmp(trim(action), SNMP_DEL))
			{
				list_for_each_safe(pos, q, &head.list)
				{
					del= list_entry(pos, struct l2tp_info, list);
				//	printf("freeing item mac_addr= -%s- vlan_id= -%s-\n", del->mac_addr, del->vlan_id);
				//	printf("vlan mac_addr= -%s- vlan_id= -%s-\n", vlan->mac_addr, vlan->vlan_id);
					if((!strcmp(del->mac_addr, vlan->mac_addr)) && (!strcmp(del->vlan_id, vlan->vlan_id)) )
					{
						vlan_num -- ;
						list_del(pos);
						free(del); /* deleting here , */
					}
				}
				status = 1 ;
			}
		}
		else {
			printf("vconfig error \n");
			status = 0 ;
			break ;
		}
		tok_vid = strtok(NULL, ",");
		
	}
	
//	free(vlan);
	return status ; //1 success ,0 failure ;	
} 

int snmp_handle_l2tp(char *parse[])
{
	char popen_r[SIZE_128] ;
	char cmd[SIZE_256] ;
	char ret[SIZE_256] ;
	char inface_vlan_id[SIZE_64] ;
	char popen_result[SIZE_256] ; 
	int macExistFlag = 0;
	int l2tpNameExistFlag = 0 ;
	struct l2tp_info *mac = NULL ;
	struct l2tp_info *del = NULL ;
	struct list_head *q;
	FILE *fp ;
	
	char *l2tp_inface_name = trim(parse[2]);
	int tunnel_id = atoi(trim(parse[3]));
	int peer_tunnel_id = atoi(trim(parse[4]));
	char *remote_ip = trim(parse[5]);
	int source_port = atoi(trim(parse[6]));
	int dest_port = atoi(trim(parse[7]));
	int session_id = atoi(trim(parse[8]));
	int peer_session_id = atoi(trim(parse[9]));
	char *mac_addr = trim(parse[10]);

	//Clear these docker .
	memset(cmd, 0, sizeof(cmd));
	memset(ret, 0, sizeof(ret));
	memset(popen_r, 0, sizeof(popen_r));
	
	//
	list_for_each(pos, &head.list)
    {
        tmp= list_entry(pos, struct l2tp_info, list);
		printf("tmp->mac_addr= %s mac_addr= %s\n", tmp->mac_addr, mac_addr);
		if (!strcmp(tmp->mac_addr, mac_addr)) //Get the l2tp_info struct as mac address.
		{
			printf("Get the same mac addr , break\n");
			mac = tmp ;
			macExistFlag ++ ;
			break ;
		}
		
        
    }
	
	if (!macExistFlag) 
	{
		printf("macaddr doesn't exist\n");
		return 0 ;
	}
	
	fp = fopen(HANDLE_L2TP_SHELL, "w");
	if(fp == 0)
	{
		perror("fopen l2tp_add.sh error");
		return 0 ;
	}
	
	if(!strcmp(trim(trim(parse[1])), SNMP_ADD)) 
	{
		
		//This is a check , check there is the same point or not.
		list_for_each(pos, &head.list)
		{
			tmp= list_entry(pos, struct l2tp_info, list);
			
			/*
				!strcmp(tmp->local_ip, local_ip) ||
				!strcmp(tmp->remote_ip, remote_ip) ||
				peer_session_id == atoi(tmp->peer_session_id) ||
				peer_tunnel_id == atoi(tmp->peer_tunnel_id) ||
			*/
			if (!strcmp(tmp->l2tp_inface_name, l2tp_inface_name) ||
				tunnel_id == atoi(tmp->tunnel_id) ||
				source_port == atoi(tmp->source_port) ||
				dest_port == atoi(tmp->dest_port) ||
				session_id == atoi(tmp->session_id) 
				) //Get the l2tp_info struct as mac address.
			{
				printf("Get the same point , break\n");
				l2tpNameExistFlag ++ ;
				//break ;
				return 0 ;
			}
			
		}
	
		fprintf(fp, ADD_L2TP_RULES,
			tunnel_id, peer_tunnel_id, localIp, remote_ip, source_port, dest_port,
			tunnel_id, session_id, peer_session_id, l2tp_inface_name, 
			l2tp_inface_name //, l2tp_inface_name
		);
	} 
	else if ( !strcmp(trim(trim(parse[1])), SNMP_DEL))
	{
	/*	sprintf(inface_vlan_id, "%s.%s", mac->inface_name, mac->vlan_id);
		sprintf(cmd ,"vconfig %s %s", SNMP_DEL, inface_vlan_id);
		printf("cmd: %s\n", cmd);
		
		fp = mypopen(cmd , 'r');
		memset(popen_result, 0 , sizeof(popen_result)) ;
		fgets(popen_result, sizeof(popen_result), fp);
		
		printf("DEL vlan result:-%s-\n", popen_result);	
		if (strcmp(popen_result, "")){
			printf("delete vlan when del l2tp error \n");
			return 0 ;
		}
		*/
		fprintf(fp, DEL_L2TP_RULES, tunnel_id, session_id, tunnel_id);
	}
	else	
	{
		printf("None action \n");
		return 0 ;
	}
	fclose(fp);
	
	if(!chmod_excute_mypopen(HANDLE_L2TP_SHELL))
	{
		printf("excute error\n");
		return 0 ;
	}
	
	printf("Excute success \n");
	//这里代码有些重复，但是在这里判断是比较准确的。待详细测试。
	if ( !strcmp(trim(trim(parse[1])), SNMP_DEL))
	{
		sprintf(inface_vlan_id, "%s.%s", mac->inface_name, mac->vlan_id);
		sprintf(cmd ,"vconfig %s %s", SNMP_DEL, inface_vlan_id);
		printf("cmd: %s\n", cmd);
		
		fp = mypopen(cmd , 'r');
		memset(popen_result, 0 , sizeof(popen_result)) ;
		fgets(popen_result, sizeof(popen_result), fp);
		
		printf("DEL vlan result:-%s-\n", popen_result);	
		if (strcmp(popen_result, "")){
			printf("delete vlan when del l2tp error \n");
			return 0 ;
		}
	}
	
	if(!strcmp(trim(trim(parse[1])), SNMP_ADD)) 
	{
		list_for_each(pos, &head.list)
		{
			tmp= list_entry(pos, struct l2tp_info, list);
			
			if (!strcmp(tmp->mac_addr, mac_addr)) //Get the l2tp_info struct as mac address.
			{
				printf("Get the same mac addr , break\n");
				
				sprintf(tmp->l2tp_inface_name, "%s", l2tp_inface_name);
				sprintf(tmp->tunnel_id, "%d", tunnel_id);
				sprintf(tmp->peer_tunnel_id, "%d", peer_tunnel_id);
				sprintf(tmp->local_ip, "%s", localIp);
				sprintf(tmp->remote_ip, "%s", remote_ip);
				sprintf(tmp->source_port, "%d", source_port);
				sprintf(tmp->dest_port, "%d", dest_port);
				sprintf(tmp->peer_tunnel_id, "%d", peer_tunnel_id);
				sprintf(tmp->session_id, "%d", session_id);
				sprintf(tmp->peer_session_id, "%d", peer_session_id);
				
				printf("snmd add l2tp_inface_name= %s local_ip= %s\n", tmp->l2tp_inface_name, tmp->local_ip);
				break ;
			}
		}
	}
	else if ( !strcmp(trim(trim(parse[1])), SNMP_DEL))
	{
		list_for_each_safe(pos, q, &head.list)
		{
			del= list_entry(pos, struct l2tp_info, list);
			if((!strcmp(del->mac_addr, mac_addr)) && (!strcmp(del->l2tp_inface_name, l2tp_inface_name)) )
			{
				vlan_num -- ;
				list_del(pos);
				free(del); /* deleting here , */
			}
		}
	}
	
	return 1 ;
}

int peer_handle_l2tp(char macaddr[], char vlan_id[], int connect, char *remoteIp)
{
	struct l2tp_info *l2tpInfo ;

	char popen_r[SIZE_128] ;
	char sendbuf[SIZE_256] ;
	char ret[SIZE_64] ;
	char cmd[SIZE_128] ;
	char l2tpname[SIZE_32] ;
	
	char *tok = NULL ;
	char *vid =  NULL ;
	int vlanID[SIZE_64]  = {0};
	
	int macEqualFlag = 0 ;
	int dport = 0 ;
	int i = 0, j = 0 ;
	
	int tunnel_id = tunnel_id_flag ;
	int session_id = session_id_flag ;
	int source_port = source_port_flag ;
	int peer_tunnel_id = tunnel_id + 1 ;
	int peer_session_id = session_id + 1 ;
	int dest_port = source_port + 1 ;
	
	printf("tunnel_id:%d, peer:%d\n", tunnel_id, peer_tunnel_id);
	FILE *fp ;//,*fp_popen

	//Clear these docker .
	memset(sendbuf, 0, sizeof(sendbuf));
	memset(l2tpname, 0, sizeof(l2tpname));
	memset(popen_r, 0, sizeof(popen_r));

	vid = (char *)malloc(strlen(vlan_id)) ;
	strcpy(vid, vlan_id);
	printf("vid:%s\n", vid);
	
	//Cut the vlan id ,and get them to a array .
	tok = strtok(vid, ",");
	while(tok != NULL)
	{
		//Make a check .
		if(atoi(tok) == 0 ) {
			printf("Unavilable vlan_id , please use number\n");
			free(vid) ;
			return 0 ;
		}
		
		//The array range is 64.
		if(i > 63)
			return 0 ;
			
		vlanID[i] = atoi(tok) ;
		printf("vlanID[%d] == %d\n",i , vlanID[i]);
		i++ ;
		tok = strtok(NULL, ",") ;
	}
	
	list_for_each(pos, &head.list)
    {
        tmp= list_entry(pos, struct l2tp_info, list);
		
		if (!strcmp(tmp->mac_addr, macaddr)) //Get the l2tp_info struct as mac address.
		{
			printf("Equal mac addr , break\n");
			macEqualFlag ++ ;
			break ;
		}
		
        //printf("read from file ,inface_name= %s vlan_id= %s\n", tmp->inface_name, tmp->vlan_id);
    }
    
	if (!macEqualFlag)
	{
		sprintf(ret, "%s", "MacAddr doesn't exist");
//		return 0 ;
	}
	
	//send tunnel id and so on info to client .
	sprintf(sendbuf, "1|%d|%d|%d|%d|%s|%s|%d|%d", 
		tunnel_id ,
		peer_tunnel_id ,
		session_id ,
		peer_session_id ,
		localIp,
		remoteIp,
		source_port ,
		dest_port
		);
	
	///After sprintf, let the value back to global varible.
	tunnel_id_flag = peer_tunnel_id + 1 ;
	session_id_flag = peer_session_id + 1;
	source_port_flag = dest_port + 1 ;
	
	write(connect, sendbuf, sizeof(sendbuf));
	
	//waiting for the l2tp data packet comming .
	dport = get_l2tp_dport(source_port-3000, remoteIp) ;
	printf("After get dport src port:%d, remote ip:%s\n", source_port-3000, remoteIp);
	printf("After get, dport:%d \n", dport);
	if(!dport) {
		printf("link timeout\n");
	//	sprintf(ret ,"link timeout") ;
		free(vid) ;
		return 0 ;
	}
	
	///Make the ip l2tp tunnel and session 
	//put the info into the l2tp_add.sh
	fp = fopen(L2TP_ADD_SHELL, "w");
	if(fp == 0)
	{
		perror("fopen l2tp_add.sh error");
		free(vid) ;
		return 0 ;
	}
	
	//Make l2tp device name ,and put it in the add shell .
	sprintf(l2tpname, "l2tpeth%d", name_flag);
	fprintf(fp, ADD_L2TP_RULES,
		tunnel_id, peer_tunnel_id, "192.168.0.30", remoteIp, source_port-3000, dport,
		tunnel_id, session_id, peer_session_id, l2tpname,  l2tpname
	);
	
	//Put iptables and ebtables rules in the l2tp_add.sh
	fprintf(fp ,ADD_IP_EBTABLE); // If In the HG2001A, This is must be insmod.
	
	fclose(fp) ;
	
	if(!chmod_excute_mypopen(L2TP_ADD_SHELL))
	{
		printf("excute error\n");
		
		///This plase ,need to add a delete shell ,to deleting the
		///added rulese .
		free(vid) ;
		return 0 ;
	}

	///This place is defined here .Not use now .
	
	int br_flag = name_flag + 1 ;
	///下面涉及到建桥的部分，暂时都使用br0.
	
/*	memset(cmd, 0, sizeof(cmd)) ;
	sprintf(cmd, "brctl addbr br%d", br_flag);
	
	if (!excute_mypopen(cmd))
	{
		printf("brctl addbr error \n");
		memset(cmd, 0, sizeof(cmd)) ;
		sprintf(cmd, "ifconfig br%d", br_flag);
		
		///If brctl addbr excute error , and the br interface doesn't exist , return 0 ;
		if(!excute_mypopen(cmd))
		{
			printf("br%d doesn't exist \n", br_flag);
		//	return 0 ; //在HEG2001A平台，暂时判断为错，如果删除br0，会造成盒子“挂掉”。
		}
		
	//	free(vid) ;
	//	return 0 ;
	}
*/	
	
	memset(cmd, 0, sizeof(cmd)) ;
	sprintf(cmd, "brctl addif br%d l2tpeth%d", 0, name_flag); //br_flag == 0 ;
	
	if (!excute_mypopen(cmd))
	{
		printf("Add l2tp to bridge error \n");
		///If excute error , delete the bridge which build up site.
		///function need the name flag , in the function ,it turn to br%d nameflag;
		excute_delbr(br_flag) ;
		free(vid) ;
		return 0 ;
	}
	
	for(j = 0; j < i; j++)
	{
		printf("vlanid :%d\n", vlanID[j]);
		///Add vlan as the vlan id (vid[j])
		memset(cmd, 0, sizeof(cmd)) ;
		sprintf(cmd, "vconfig add eth0 %d", vlanID[j]);
		
		if (!excute_mypopen(cmd)){
			printf("Vlan add error \n");
			excute_delbr(br_flag) ;
			free(vid) ;
			return 0 ;
		}
		
		///Add the vlan to bridge.
		memset(cmd, 0, sizeof(cmd)) ;
		sprintf(cmd, "brctl addif br%d eth0.%d", 0, vlanID[j]); // br_flag === 0;
		
		if (!excute_mypopen(cmd)){
			printf("Vlan add error \n");
			excute_delbr(br_flag) ;
			free(vid) ;
			return 0 ;
		}
	}
	
	//And put the data into link list .
	l2tpInfo = (struct l2tp_info *)malloc(sizeof(struct l2tp_info));
	
	sprintf(l2tpInfo->l2tp_inface_name, "l2tpeth%d", name_flag);
	sprintf(l2tpInfo->tunnel_id, "%d", tunnel_id);
	sprintf(l2tpInfo->peer_tunnel_id, "%d", peer_tunnel_id);
	sprintf(l2tpInfo->session_id, "%d", session_id);
	sprintf(l2tpInfo->peer_session_id, "%d", peer_session_id);
	sprintf(l2tpInfo->local_ip, "%s", localIp);
	sprintf(l2tpInfo->remote_ip, "%s", remoteIp);
	sprintf(l2tpInfo->source_port, "%d", source_port);
	sprintf(l2tpInfo->dest_port, "%d", dport);
	sprintf(l2tpInfo->mac_addr, "%s", macaddr);
	sprintf(l2tpInfo->inface_name, "%s", "eth0 ");
	sprintf(l2tpInfo->vlan_id, "%s", vlan_id);
	
	list_add(&(l2tpInfo->list), &(head.list));
	printf("after add to the list \n");
	
	name_flag += 1 ;
	printf("nameflag:%d\n", name_flag);
	
	printf("before sprintf\n");
	sprintf(ret, "%s", "success") ;
	printf("return %s sunccess\n", ret);

	free(vid) ;
	//if the l2tp build success , return 1 .
	return 1 ;
}

int hand_peer_dsl_recover(char macaddr[])
{
	struct l2tp_info *del = NULL;
	char *tok = NULL ;
	char cmd[SIZE_128] ;
	
	list_for_each(pos, &head.list)
    {
        del= list_entry(pos, struct l2tp_info, list);
		printf("del->mac_addr= %s mac_addr= %s\n", del->mac_addr, macaddr);
		if (!strcmp(del->mac_addr, macaddr)) //Get the l2tp_info struct as mac address.
		{	
		
			printf("Get the same mac addr , break\n");
			list_del(pos) ;
			printf("After delete the pos in link_list\n");
			
			tok = strtok(del->vlan_id, ",");
			while(tok != NULL)
			{
			//	vlanID[i] = tok ;
				printf("tok == %s\n" , tok);
				
				memset(cmd, 0, sizeof(cmd)) ;
				sprintf(cmd, "vconfig rem eth0.%s", tok);
				
				if (!excute_mypopen(cmd))
				{
					printf("delete eth0.%s error \n", tok);
				}
				tok = strtok(NULL, ",") ;
			}
			
			memset(cmd, 0, sizeof(cmd)) ;
			sprintf(cmd, "ip l2tp del session tunnel_id %s session_id %s", del->tunnel_id, del->session_id);
			
			if (!excute_mypopen(cmd))
			{
				printf("delete ip l2tp session error \n");
			}
			
			memset(cmd, 0, sizeof(cmd)) ;
			sprintf(cmd, "ip l2tp del tunnel tunnel_id %s", del->tunnel_id);
			
			if (!excute_mypopen(cmd))
			{
				printf("delete ip l2tp tunnel error \n");
			}
			
			break ;
		}

	//	free(del);
    }
	
	return 1; 
}

void *handle_snmp_message(void *arg)
{
	printf("starting receive message... \n");
	
    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
	int i = 0, j = 0 ;
	int conn = 0 ;
	int status = 0 ; 
	//char ret[SIZE_64] ;
	char ret[SIZE_64]  ;
	char *print = NULL ;
	char *tok = NULL ;
	char *parse[20]  = {NULL};
	
	FILE *fs ;
	
	//create socket ;
	create_sokect(server_sockfd, SNMP_LISTEN_PORT) ;
	
    ///client socket
    char buffer[BUFFER_SIZE];
    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);
	
    while(1)
    {
		///If success, return >= 0 , else return -1 ;
		conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
		if(conn<0)
		{
			perror("connect");
			exit(1);
		}
		
		char *addr = (char *)inet_ntoa(client_addr.sin_addr);
		printf("connect from:%s, %d\n", addr, ntohs(client_addr.sin_port));
	
        memset(buffer,0,sizeof(buffer));
		/*	This is a judge, buffer NULL can't into this while.*/
		
        while(read(conn, buffer, sizeof(buffer)) >0 )
		{
			//Initilaze the i , other i will add always ...
			printf("recv buffer:-%s-...\n", buffer);
			memset(ret, 0, sizeof(ret));
			
			fs = fopen("/tmp/l2tp.dat", "w");
			if(fs == NULL)
			{
				printf("open l2tp error \n");
				return 0 ;
			}
			
			i = 0 ;
			tok = strtok(buffer, "|");
			while(tok != NULL)
			{
				parse[i] = tok ;
				printf("parse[%d] : %s\n",i, parse[i]);
				i++ ;
				tok = strtok(NULL, "|") ;
			}
			
			/* parse[0] is diff this message is handling
			*	VLAN or L2TP . 1 == VLAN ; 2 == L2TP
			*/
			
			//memset(ret, 0, sizeof(ret)) ;
			if(!strcmp(trim(parse[0]), SNMP_VLAN_H)) 
			{
			//	printf("before handle vlan \n");
				status = snmp_handle_vlan(parse);
				if(status)
					sprintf(ret, "%s|%s|%s", trim(parse[0]), trim(parse[1]), "success") ;
				else
					sprintf(ret, "%s|%s|%s", trim(parse[0]),trim(parse[1]), "failed") ;
			} 
			else if (!strcmp(trim(parse[0]), SNMP_L2TP_H)) 
			{
				printf("Handle l2tp \n");
				//ret = (char *)malloc(SIZE_64);
				status = snmp_handle_l2tp(parse);
				if(status)
					sprintf(ret, "%s|%s|%s", trim(parse[0]), trim(parse[1]), "success") ;
				else
					sprintf(ret, "%s|%s|%s", trim(parse[0]),trim(parse[1]), "failed") ;
			} 
			else if (!strcmp(trim(parse[0]), SNMP_PUBLIC_IP_CHANGE)) 
			{
				
				memset(localIp, 0, sizeof(localIp));
				sprintf(localIp, "%s", trim(parse[1])); //Here is for other use this ip ;
				change_public_ip(localIp) ; // Here is change the struct's local ip .
				printf("change public ip:%s, success \n", localIp);
				sprintf(ret, "%s", "change public ip success");
			} 
			else if(!strcmp(trim(parse[0]), SNMP_SHOW_VLAN))
			{
				//printf("Show commond \n");
				
				print = (char *)malloc(sizeof(struct l2tp_info) + SIZE_32);
				
				sprintf(ret, "%s", "showEnd");
				
				list_for_each_entry(tmp, &head.list, list)
				{	
					//memset(print, 0, sizeof(print));
					sprintf(print, "showResult| %s| %s| %s| %s| %s| %s| %s| %s| %s| %s| %s| %s",
						tmp->l2tp_inface_name ,
						tmp->tunnel_id ,
						tmp->peer_tunnel_id ,
						tmp->session_id ,
						tmp->peer_session_id ,
						tmp->local_ip ,
						tmp->remote_ip ,
						tmp->source_port ,
						tmp->dest_port ,
						tmp->mac_addr ,
						tmp->inface_name ,
						tmp->vlan_id 
						);
					printf("print:%s\n", print);
					
					//write(conn, print, strlen(print));
					send(conn, print, strlen(print), 0);
					printf("send end \n");
					usleep(50000);
					//sleep(5);
				}
				
				printf("---------------\n");
				//printf("ret:%s\n", ret);
				
				if (print != NULL)
					free(print);
			}
			else 
			{
			//	printf("Invalid operation \n");
			//	ret = (char *)malloc(SIZE_32);
				sprintf(ret, "%s", "Invalid operation");
			}
			
			list_for_each_entry(tmp, &head.list, list)
			{	
				//usleep(100);
				if(fwrite(tmp, sizeof(struct l2tp_info), 1, fs ) != 1)
					printf("fwrite error \n");
				
				printf("write in file .Inface_name= %s vlan_id= %s mac_addr= %s local_ip:%s\n", 
						tmp->inface_name, tmp->vlan_id, tmp->mac_addr, tmp->local_ip);
			}
			
			// Make the parse all NULL ;
			for (j = 0; j < i ;j ++)
			{
				parse[i] = NULL ;
			}
			
			printf("ret:%s\n", ret);
			write(conn, ret, strlen(ret));
				
			fclose(fs);
			memset(buffer,0,sizeof(buffer)); // Every cycle must be init .
		}
		close(conn);
    }
	
    close(server_sockfd);
	
	return 0 ;
}

void *handle_peer_message()
{
	printf("handle_peer_message...\n");
	int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
	int conn = 0 ;
	int i = 0, j = 0 ;
	int status = 0 ;
	char ret[SIZE_128] ;
	char *tok = NULL ;
	char *parse[20]  = {NULL};
	
	FILE *fs ;
	
    //create socket 
	create_sokect(server_sockfd, PEER_LISTEN_PORT);
	
	char buffer[BUFFER_SIZE];
    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);
	
    while(1)
    {
		//accept everytime .
		conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
		if(conn<0)
		{
			perror("connect");
			exit(1);
		}
		
		char *remoteaddr = (char *)inet_ntoa(client_addr.sin_addr);
		printf("connect from:%s, port:%d\n", remoteaddr, ntohs(client_addr.sin_port));
	
        memset(buffer,0,sizeof(buffer));
		
		/*	This is a judge, buffer NULL can't into this while.*/
        while(read(conn, buffer, sizeof(buffer)) >0 )
		{
			///Open the l2tp data file .
			fs = fopen("/tmp/l2tp.dat", "w");
			if(fs == NULL)
			{
				printf("open l2tp error \n");
				return 0 ;
			}
		
			//Initilaze the i , other i will add always ...
			memset(ret, 0, sizeof(ret));
			
			// Make the parse all NULL ;
			for (j = 0; j < 20 ;j ++)
			{
				parse[i] = NULL ;
			}
			
			i = 0 ;
			printf("recv buf:%s\n", buffer);
			tok = strtok(buffer, "|");
			while(tok != NULL)
			{
				parse[i] = tok ;
				printf("parse[%d] == %s\n",i , tok);
				i++ ;
				tok = strtok(NULL, "|") ;
			}
			
			/* parse[0] is diff this message is handling
			*	VLAN or L2TP . 1 == VLAN ; 2 == L2TP
			*/
			
			if(!strcmp(parse[0], PEER_REQUST))
			{
				printf("handle peer request, macaddr:%s \n", parse[1]);
				
				if(parse[1] == NULL) 
				{
					printf("MacAddr NULL, return \n");
					sprintf(ret, "NO Macaddr");
				}
				else if (parse[2] == NULL) 
				{
					printf("Vlan ID NULL, return \n");
					sprintf(ret, "NO vlan id input");
				}
				else {
					///Send macaddr:parse[1], vlan_id:parse[2] to the peer_handle function.
					status = peer_handle_l2tp(parse[1], parse[2], conn, remoteaddr);
					printf("status:%d\n", status);
					if(status)
						sprintf(ret, "%s", "l2tp Add success");
					else
						sprintf(ret, "%s", "l2tp Add failed");
					
					printf("After peer handle l2tp\n");
				}
			}
			else if (!strcmp(parse[0], PEER_DSL_RECOVER))
			{
				printf("Link_recover...\n");
				hand_peer_dsl_recover(parse[1]) ;
				sprintf(ret, "%s", "Link recover ");
			}
			else
			{
				sprintf(ret, "%s", "Invalid operation");
			}
			
			list_for_each_entry(tmp, &head.list, list)
			{	
				//usleep(100);
				if(fwrite(tmp, sizeof(struct l2tp_info), 1, fs ) != 1)
					printf("fwrite error \n");
				
				printf("print the list, Inface_name= %s vlan_id= %s mac_addr= %s local_ip:%s\n", 
						tmp->inface_name, tmp->vlan_id, tmp->mac_addr, tmp->local_ip);
			}
			
			fclose(fs);
			
			memset(buffer,0,sizeof(buffer));
			
			printf("ret:%s \n", ret);
			write(conn, ret, strlen(ret));
			printf("After write \n");
		}
		close(conn);
    }
    //close(conn);
    close(server_sockfd);
	
	return 0 ;
	
}

int main()
{
	pthread_t pid_snmp;
	pthread_t pid_peer;
	
//	struct  l2tp_info *tmp ;
	struct list_head *pos;
	char *tok = NULL ;
	char vId[SIZE_128] ;
	char cmd[SIZE_64] ;
	
	int br_flag = 0 ;
	
	FILE *fp, *fs ;
	
	//All init working.
	vlan_num = 0 ;//init the vlan number ;
	INIT_LIST_HEAD(&head.list); 
	tunnel_id_flag = 100;
	session_id_flag = 10000;
	source_port_flag = 3093;
	name_flag = 0 ;
	
	
	/* Check the data file exist or not ?
	*	If it's not exist, we will make one.
	*/
	if((access("/tmp/l2tp.dat",F_OK))== -1)   
	{   
		printf("l2tp.dat not exist , make it \n");
		system("touch /tmp/l2tp.dat");  
	}
	
	//Then open the data file .Failure ,return 0 ;
	fp = fopen("/tmp/l2tp.dat", "r");
	if(fp == NULL)
	{
		printf("open l2tp.dat error, return \n");
		return 0 ;
	}
	
	while(!feof(fp))
    {
        tmp= (struct l2tp_info *)malloc(sizeof(struct l2tp_info));

		fread(tmp, sizeof(struct l2tp_info),1 ,fp) ;
	//	printf("tmp->mac: -%s-\n", tmp->mac_addr);
		if(strcmp(tmp->mac_addr, ""))  //mac is the must be exist.
		{
			list_add_tail(&(tmp->list), &(head.list));
			
			///Get the local ip ;
			sprintf(localIp, "%s", trim(tmp->local_ip));
			
			///Get the tunnel id , session id ,source port flag. And compare with the const.
			tunnel_id_flag = atoi(tmp->tunnel_id)+2 < tunnel_id_flag ? tunnel_id_flag:atoi(tmp->tunnel_id)+2 ;
			session_id_flag = atoi(tmp->session_id)+2 < session_id_flag ? session_id_flag:atoi(tmp->session_id)+2 ;
			source_port_flag= atoi(tmp->source_port)+2 < source_port_flag ? source_port_flag:atoi(tmp->source_port)+2 ;
			sscanf(tmp->l2tp_inface_name, "l2tpeth%d", &name_flag) ;//Get the name_flag out from l2tp inface name.
			name_flag += 1 ;
			
			br_flag = name_flag + 1;
			printf("br_flag:%d\n", br_flag);
					
			fs = fopen(L2TP_ADD_SHELL, "w");
			if(fs == 0)
			{
				perror("fopen l2tp_add.sh error");
				return 0 ;
			}
			
			//Make l2tp device name ,and put it in the add shell .
			//sprintf(l2tpname, "l2tpeth%d", name_flag);
			fprintf(fs, ADD_L2TP_RULES,
				atoi(tmp->tunnel_id), atoi(tmp->peer_tunnel_id), "192.168.0.30", tmp->remote_ip, 
				atoi(tmp->source_port)-3000, atoi(tmp->dest_port), atoi(tmp->tunnel_id), atoi(tmp->session_id), 
				atoi(tmp->peer_session_id), tmp->l2tp_inface_name, tmp->l2tp_inface_name
			);
			
			//Put iptables and ebtables rules in the l2tp_add.sh
			fprintf(fs ,ADD_IP_EBTABLE); // If In the HG2001A, This is must be insmod.EBTABLE and iptables.
			
			fclose(fs) ;
			
			if(!chmod_excute_mypopen(L2TP_ADD_SHELL))
			{
				printf("L2tp shell excute error, tunnel id:%s. \n", tmp->tunnel_id);
				
				///This plase ,need to add a delete shell ,to deleting the
				///added rulese .
			//	return 0 ;
			}
			
			memset(cmd, 0, sizeof(cmd)) ;
			sprintf(cmd, "brctl addif br%d %s", 0, tmp->l2tp_inface_name);
			
			if (!excute_mypopen(cmd)){
				printf("Vlan add error \n");
			//	excute_delbr(br_flag) ;
			}
			
			memset(vId, 0, sizeof(vId));
			if(strlen(tmp->vlan_id) < 128)
				sprintf(vId, "%s", tmp->vlan_id);
			
			tok = strtok(vId, ",");
			while(tok != NULL)
			{	
				printf("vlanID == %d\n", atoi(tok));
				
				memset(cmd, 0, sizeof(cmd)) ;
				sprintf(cmd, "vconfig add eth0 %s", tok);
				
				if (!excute_mypopen(cmd)){
					printf("Vlan add error \n");
				//	excute_delbr(br_flag) ;
				}
				
				///Add the vlan to bridge.
				memset(cmd, 0, sizeof(cmd)) ;
				///On the HEG2001, All vlan insert into br0 .
				sprintf(cmd, "brctl addif br%d eth0.%s", 0, tok);
				
				if (!excute_mypopen(cmd)){
					printf("Vlan add error \n");
				//	excute_delbr(br_flag) ;
				}
				
				tok = strtok(NULL, ",") ;
			}
			
			printf("tun:%d, ses:%d, sou:%d ,name:%d\n", tunnel_id_flag, session_id_flag, source_port_flag, name_flag) ;
		}
    }
	
//	printf("traversing the list using list_for_each()\n");
    list_for_each(pos, &head.list)
    {
        tmp= list_entry(pos, struct l2tp_info, list);
		
        printf("read inface_name= %s vlan_id= %s\n", tmp->inface_name, tmp->vlan_id);
    }
    printf("\n");
	
	fclose(fp);
	
	if (pthread_create(&pid_snmp, NULL, handle_snmp_message, NULL) != 0) {
		printf("Create thread peer error!\n");
		exit(1);
	}
	
	if (pthread_create(&pid_peer, NULL, handle_peer_message, NULL) != 0) {
		printf("Create thread peer error!\n");
		exit(1);
	}
	
	if (pthread_join(pid_snmp,NULL)!=0)
	{
 		printf("Join thread snmp error!\n");
 		exit(1);
 	}
	else
       	printf("Thread snmp Joined!\n");

	if (pthread_join(pid_peer,NULL)!=0)
	{
 		printf("Join thread peer error!\n");
 		exit(1);
 	}
	else
       	printf("Thread peer Joined!\n");
		
	
    return 0;
}

